package online.zhangwenzhe.common.security.Impl;

import online.zhangwenzhe.common.exception.BusinessException;
import online.zhangwenzhe.common.exception.BusinessExceptionResult;
import online.zhangwenzhe.common.exception.GlobalExceptionHandler;
import online.zhangwenzhe.common.security.TokenInformation;
import online.zhangwenzhe.common.security.TokenVerifier;
import online.zhangwenzhe.common.CustomProperties;
import online.zhangwenzhe.common.security.UserDetails;
import org.apache.catalina.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Map;
import java.util.Base64;

/**
 * 说明：
 *
 * @author 张文哲
 * @version 1.0.0
 * @since 2018/7/3 16:25
 */

@Component
public class TokenVerifierRemoteImpl implements TokenVerifier {
    protected static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    RestTemplate restTemplate;
    private CustomProperties customProperties;

    String checkTokenEndpoint = "http://localhost:8080/oauth/check_token";
    String client_id = "app";
    String client_secret = "secret";

    @Autowired
    public TokenVerifierRemoteImpl(CustomProperties customProperties) {
        try {
            this.checkTokenEndpoint = customProperties.getOauth2().getTokenEndpoint();
            this.client_id = customProperties.getOauth2().getClientId();
            this.client_secret = customProperties.getOauth2().getClientSecret();
        } catch (Exception e) {
            logger.warn("OAuth2.0验证没有配置");
        }
        this.restTemplate = new RestTemplate();
    }

    @Override
    public UserDetails verify(String token) {
        String basicAuthHeader = generateBasicAuthHeaderString(client_id, client_secret);

        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("Authorization", basicAuthHeader);
        HttpEntity<String> requestEntity = new HttpEntity<String>(null, requestHeaders);

        UserDetails userDetails = null;

        try {
            ResponseEntity<Map> response = restTemplate.exchange(checkTokenEndpoint + "?token=" + token, HttpMethod.GET, requestEntity, Map.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody().get("user_name") != null) {
                userDetails = new UserDetails();
                userDetails.setUserId(Long.valueOf(response.getBody().get("user_name").toString()));
                userDetails.setClient(response.getBody().get("client_id").toString());
            }
        } catch (HttpClientErrorException e) {
            // Token无效
            return null;
        } catch (Exception e) {
            // http和认证服务器通信异常
            throw new BusinessException(new BusinessExceptionResult("90001", "用户认证服务器通信异常"));
        }

        return userDetails;
    }

    // Authorization : Basic XXXXXXXXXX
    private String generateBasicAuthHeaderString(String client_id, String client_secret) {
        try {
            String base = "";
            if (client_secret == null
                    || client_secret.equals("")) {
                base = encodeURIComponent(client_id);
            } else {
                base = encodeURIComponent(client_id) + ":"
                        + encodeURIComponent(client_secret);
            }

            return "Basic " + Base64.getEncoder().encodeToString(base.getBytes("UTF-8"));

        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    // URL Encoding Utility
    private String encodeURIComponent(String s) {
        String result;

        try {
            result = URLEncoder.encode(s, "UTF-8").replaceAll("\\+", "%20")
                    .replaceAll("\\%21", "!").replaceAll("\\%27", "'")
                    .replaceAll("\\%28", "(").replaceAll("\\%29", ")")
                    .replaceAll("\\%7E", "~");
        } catch (UnsupportedEncodingException e) {
            result = s;
        }

        return result;
    }
}
